home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
haeberli
/
libgutil
/
polyscan.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
6KB
|
311 lines
/*
* Copyright 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* polyscan -
* Polygon scanline rendering for characters.
*
* exports:
void scanoutspan(void(*func)(int y, int x1, int x2))
void scanoutlinewidth(float width)
void scanbeginfacet(void)
void scanendfacet(void)
void scanvertex(float x, float y)
void scanbeginscan(void)
void scanendscan(void)
*
* In general the floating point coordinate 0.0,0.0 maps to
* the center of pixel [0,0]. Here is an example of this
* sampling:
*
*
* scanbeginscan();
* scanvertex(-0.5,-0.5);
* scanvertex( 0.5,-0.5);
* scanvertex( 0.5, 0.5);
* scanvertex(-0.5, 0.5);
* scanendscan();
*
* Fills pixel [0,0]
*
* Paul Haeberli - 1992
*/
#include "stdio.h"
#include "math.h"
#include "polyscan.h"
#define NBUCKETS (20)
#define TOLERANCE (0.0000001)
#define NINCHUNK (40)
typedef struct edge {
struct edge *next;
float ymax;
float ymin;
float x, y;
float dxdy;
} Edge;
static void deffillspan(int y,int x1,int x2)
{
printf("fillspan y: %d x range: %d to %d inclusive\n",y,x1,x2);
}
static Edge *edges, *active, *fedges;
static Edge *buckets[NBUCKETS];
static int npoints;
static Edge start, current, last;
static float outlinewidth = 0.0;
static float xmin, xmax;
static float ymin, ymax;
static float ymin, ymax;
static float ymin, ymax;
static void (*fillspan)(int y, int x1, int x2) = deffillspan;
void scanoutspan(void(*func)(int y, int x1, int x2))
{
fillspan = func;
}
static setpix(unsigned int x, unsigned int y)
{
(fillspan)(y,x,x);
}
static void freeedge(Edge *e)
{
if( e ) {
e->next = fedges;
fedges = e;
}
}
static Edge *newedge(void)
{
Edge *e;
int i;
if(!fedges) {
e = (Edge *)mymalloc(NINCHUNK*sizeof(Edge));
for(i=0; i<NINCHUNK; i++)
freeedge(e++);
}
e = fedges;
fedges = fedges->next;
return e;
}
static void createedge(Edge *e1, Edge *e2)
{
Edge *top, *bot;
Edge *e, *b;
int bucketno;
float xstart, ystart;
float xend, yend;
float dy, ady;
if(outlinewidth>0.0) {
trappixel_callback(setpix);
subpixline(e1->x-1.0,e1->y,e2->x-1.0,e2->y,outlinewidth);
}
if(e1->y>e2->y) {
top = e1;
bot = e2;
} else {
top = e2;
bot = e1;
}
ady = dy = top->y-bot->y;
if(ady<0.0)
ady = 0.0;
if(ady < TOLERANCE)
return;
e = newedge();
e->ymax = top->y;
e->ymin = bot->y;
e->dxdy = (top->x-bot->x)/dy;
e->x = bot->x;
e->next = edges;
edges = e;
}
void scanoutlinewidth(float width)
{
outlinewidth = width;
}
void scanbeginfacet(void)
{
npoints = 0;
}
void scanendfacet(void)
{
if(npoints>0)
createedge(&last,&start);
npoints = 0;
}
void scanvertex(float x, float y)
{
x = x+1.0;
if(npoints++ == 0) {
start = current;
start.x = x;
start.y = y;
last = start;
} else {
current.x = x;
current.y = y;
createedge(&last,¤t);
last = current;
}
if(edges == 0) {
xmin = xmax = x;
ymin = ymax = y;
} else {
if(x<xmin) xmin = x;
if(y<ymin) ymin = y;
if(x>xmax) xmax = x;
if(y>ymax) ymax = y;
}
}
void scanbeginscan(void)
{
int i;
edges = NULL;
active = NULL;
for(i=0; i<NBUCKETS; i++)
buckets[i] = NULL;
scanbeginfacet();
}
void scanendscan(void)
{
Edge *last, *span, *temp, *newspan;
Edge *b, *e, *ne;
int i, iy, xchg, x1, x2, scrymin, scrymax;
float y, ydelta;
scanendfacet();
if(!edges)
return;
ydelta = ymax-ymin+0.1;
/* insert spans in buckets */
span = edges;
while(span) {
newspan = span->next;
temp = (Edge *)&buckets[(int)((span->ymin-ymin)*(NBUCKETS-1)/ydelta)];
y = span->ymin;
while(temp->next && (y > temp->next->ymin))
temp = temp->next;
span->next = temp->next;
temp->next = span;
span = newspan;
}
/* link buckets together */
edges = NULL;
last = (Edge *)&edges;
for(i=0; i<NBUCKETS; i++) {
if( (span=buckets[i]) != NULL ) {
last->next = span;
while(span->next)
span = span->next;
last = span;
}
}
/* scan convert now!! */
scrymin = floor(ymin);
scrymax = floor(ymax);
for(iy=scrymin; iy<=scrymax; iy++) {
y = iy;
/* remove old spans */
for( span = (Edge *)&active; span->next; ) {
if (span->next->ymax <= y) {
temp = span->next;
span->next = temp->next;
freeedge(temp);
} else
span = span->next;
}
/* add new spans */
temp = edges;
while(temp && (temp->ymin <= y)) {
newspan = temp;
temp = temp->next;
if(newspan->ymax > y) {
newspan->x -= newspan->dxdy * (newspan->ymin - y);
span = (Edge *)&active;
while(span->next && (span->next->x < newspan->x) )
span = span->next;
newspan->next = span->next;
span->next = newspan;
}
}
edges = temp;
/* order spans */
if(active) {
do {
xchg = 0;
span = (Edge *)&active;
while(span->next && span->next->next) {
while(span->next->next ) {
if (span->next->x > span->next->next->x) {
temp = span->next;
span->next = temp->next;
temp->next = temp->next->next;
span->next->next = temp;
xchg++;
}
span=span->next;
}
span=span->next;
}
} while( xchg );
/* fill spans */
for(span=active; span && span->next; span=span->next->next) {
x1 = span->x; x2 = span->next->x;
if(x2 > x1)
fillspan(iy,x1,x2-1);
}
/* increment spans */
for( span = active; span; span = span->next )
span->x += (span->dxdy);
}
}
while(active) {
temp = active;
active = active->next;
freeedge(temp);
}
while(edges) {
temp = edges;
edges = edges->next;
freeedge(temp);
}
}